// Copyright (c) 2023 Presto Labs Pte. Ltd.
// Author: tianqiang

#pragma once

#include <memory>
#include <string_view>

#include "coin2/exchange/base/order/rate_config.h"
#include "coin2/exchange/base/order/rate_tracker.h"

namespace coin2::exchange::mexc::api_util_v3 {

class MexcRateTracker : public coin2::exchange::base::order::IRateTracker {
 public:
  using FixedWindowRateTracker = coin2::exchange::base::order::FixedWindowRateTracker;
  using RateConfig = coin2::exchange::base::order::RateConfig;
  using RateLimitReportWriter = coin2::exchange::base::order::RateLimitReportWriter;
  using ActionType = coin2::exchange::base::order::IRateTracker::ActionType;
  using OrderConnectionConfig = coin2::exchange::order::OrderConnectionConfig;
  using RateLimitInfoSpotMexc = coin2::exchange::order::RateLimitInfoSpotMexc;

 public:
  explicit MexcRateTracker(const MarketExchangeApi& mea, const OrderConnectionConfig& cfg);

  bool HasEnoughRateLimit(int64_t timestamp, ActionType action_type) override;
  void Push(int32_t num_reqs, int64_t timestamp, ActionType action_type) override {}
  void ParseRateLimitInfo(const std::shared_ptr<AsioHttpContext>&, ActionType) override {}
  void SetRateLimitInfo(int32_t rate_limit, int32_t rate_limit_remaining) override { CHECK(false); }
  void SetRateLimitInfoString(const google::protobuf::Message* message) override;
  void WriteRateLimitReportMessage(OrderLoggerCB callback) override;
  double GetMaxRateUsedRatio(int64_t timestamp, ActionType action_type) override;

  void Push(int64_t timestamp, int64_t ip_weight, int64_t uid_weight);
  void UpdateEnableTime(int64_t enable_time) { enable_time_ = enable_time; }

 private:
  void InitRateTracker(
      RateLimitInfoSpotMexc* rate_config,
      std::string_view mea_str,
      std::string_view example);

  double GetMaxRateUsedRatio(
      const std::unique_ptr<FixedWindowRateTracker>& rate_tracker,
      int64_t timestamp) {
    double rate_used_ratios = 0.0;
    if (rate_tracker) {
      auto max_reqs = rate_tracker->MaxReq();
      auto remaining = rate_tracker->GetRemaining(timestamp);
      if (max_reqs > 0) {
        rate_used_ratios = 1.0 * (max_reqs - remaining) / max_reqs;
      }
    }
    return rate_used_ratios;
  }
  bool CheckEnableTime(int64_t timestamp, ActionType action_type);
  bool CheckRateLimit(int64_t timestamp, ActionType action_type);

 private:
  int64_t enable_time_ = 0;
  std::unique_ptr<FixedWindowRateTracker> rate_tracker_uid_;
  std::unique_ptr<FixedWindowRateTracker> rate_tracker_ip_;
  std::unique_ptr<RateLimitReportWriter> rate_limit_report_writer_ = {};
};

}  // namespace coin2::exchange::mexc::api_util_v3
